import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart';
import 'package:sqflite_sqlcipher/sqflite_sqlcipher.dart';
import 'package:sqflite_sqlcipher/sql.dart';
import 'package:sqflite_sqlcipher_example/open_test_page.dart';

import 'package:sqflite_sqlcipher/sqflite_sqlcipher.dart' as sqflite;
import 'package:sqflite_sqlcipher_example/utils.dart';

import 'test_page.dart';

/// Cipher test page.
class SqlCipherTestPage extends TestPage {
  /// Cipher test page.
  SqlCipherTestPage() : super('SqlCipher tests') {
    test('Open and query database', () async {
      var path = await initDeleteDb('encrypted.db', securityLevel: SecurityLevel.s4);
      const password = '1234';

      var db = await openDatabase(
        path,
        password: password,
        version: 1,
        securityLevel: SecurityLevel.s4,
        onCreate: (db, version) async {
          var batch = db.batch();

          batch.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, text NAME)');
          await batch.commit();
        },
      );

      try {
        expect(await db.rawInsert('INSERT INTO Test (text) VALUES (?)', ['test']), 1);
        var result = await db.query('Test');
        var expected = [
          {'id': 1, 'text': 'test'}
        ];
        print(result);
        expect(result, expected);
        expect(await isDatabase(path, password: password), isTrue);
      } finally {
        await db.close();
      }
      expect(await isDatabase(path, password: password), isTrue);
    });

    test('Open asset database', () async {
      var databasesPath = await getDatabasesPath();
      var path = join(databasesPath, 'asset_example.db');

      // delete existing if any
      await deleteDatabase(path);

      // Make sure the parent directory exists
      var copyPath = await getFilePath(path, 'asset_example.db');
      try {
        await Directory(dirname(copyPath)).create(recursive: true);
      } catch (_) {}

      // Copy from asset. HarmonyOS 不支持自定义密码，因此无法复制加密数据库
      var data = await rootBundle.load(join('assets', isOhos() ? 'example.db' : 'example_pass_1234.db'));
      List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      // Write and flush the bytes written
      await File(copyPath).writeAsBytes(bytes, flush: true);

      // open the database
      var db = await openDatabase(path, password: '1234', securityLevel: SecurityLevel.s4, encrypt: false);

      // Our database as a single table with a single element
      List<Map<String, dynamic>> list = await db.rawQuery('SELECT * FROM Test');
      print(list);
      expect(list.first['name'], 'simple value');

      await db.close();
    });

    test('Open asset database (SQLCipher 3.x, cipher_migrate on Android)', () async {
      var databasesPath = await getDatabasesPath();
      var path = join(databasesPath, 'asset_example_3x.db');

      // delete existing if any
      await deleteDatabase(path);

      // Make sure the parent directory exists
      var copyPath = await getFilePath(path, 'asset_example_3x.db');
      try {
        await Directory(dirname(copyPath)).create(recursive: true);
      } catch (_) {}

      // Copy from asset. HarmonyOS 不支持自定义密码，因此无法复制加密数据库。iOS不支持SqliteCipher 3.x
      var data = await rootBundle.load(join('assets', isOhos() ? 'issue_64.db' : (Platform.isIOS ? 'example_pass_1234.db' : 'sqlcipher-3.0-testkey.db')));
      List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      // Write and flush the bytes written
      await File(copyPath).writeAsBytes(bytes, flush: true);

      // open the database
      var db = await openDatabase(path, password: Platform.isIOS ? '1234' : 'testkey', securityLevel: SecurityLevel.s4, encrypt: false);

      // Our database as a single table with a single element
      var sql = (isOhos() ? 'SELECT * FROM speakers' : (Platform.isIOS ? 'SELECT * FROM Test' : 'SELECT * FROM t1'));
      List<Map<String, dynamic>> list = await db.rawQuery(sql);
      print(list);
      expect(list.length, greaterThan(0));

      await db.close();
    });

    test('Open an unencrypted database with the package sqflite', () async {
      String path = await initDeleteDb("unencrypted.db");

      Database db = await sqflite.openDatabase(
        path,
        version: 1,
        encrypt: false,
        onCreate: (db, version) async {
          Batch batch = db.batch();

          batch.execute("CREATE TABLE Test (id INTEGER PRIMARY KEY, text NAME)");
          await batch.commit();
        },
      );

      try {
        expect(await db.rawInsert("INSERT INTO Test (text) VALUES (?)", ['test']), 1);
        var result = await db.query("Test");
        List expected = [
          {'id': 1, 'text': 'test'}
        ];
        print(result);
        expect(result, expected);
      } finally {
        await db.close();
      }
    });
  }
}
